#include "MainFrame.h"
#include <regex>

static bool controlAllFlag=false;

MainFrame::MainFrame() : wxFrame(nullptr,wxID_ANY,wxT("服务端"))
{

    wxSizer* mainSizer=new wxBoxSizer(wxHORIZONTAL);
    wxSizer* sideBarSizer=new wxBoxSizer(wxVERTICAL);
    wxSizer* cameraControl=new wxFlexGridSizer(2,5,5);
    txtInf=new wxStaticText(this,(int)MainFrameID::txtInf,wxT("端口启动在7600上"));
    btnInitDevice=new wxButton(this,(int)MainFrameID::btnInitDevice,wxT("初始化设备"));
    btnStartShot=new wxButton(this,(int)MainFrameID::btnStartShot,wxT("开始拍摄"));
    btnStartSave=new wxButton(this,(int)MainFrameID::btnStartSave,wxT("开始存图"));
    btnGetDeviceStatus=new wxButton(this,(int)MainFrameID::btnGetDeviceStatus,wxT("获取设备状态"));
    displayArea=new ImageDisplay(this);
    deviceList=new wxListCtrl(this,(int)MainFrameID::deviceList,wxDefaultPosition,wxDefaultSize,wxLC_REPORT);
    chkCameraTrigger=new wxCheckBox(this,(int)MainFrameID::chkCameraTrigger,wxT("硬件触发"));
    spinImageHeight=new wxSpinCtrl(this,(int)MainFrameID::spinImageHeight);
    spinImageWidth=new wxSpinCtrl(this,(int)MainFrameID::spinImageWidth);
    spinImageXOffset=new wxSpinCtrl(this,(int)MainFrameID::spinImageXOffset);
    spinImageYOffset=new wxSpinCtrl(this,(int)MainFrameID::spinImageYOffset);
    spinExposureTime=new wxSpinCtrl(this,(int)MainFrameID::spinExposureTime);
    spinFrameControl=new wxSpinCtrl(this,(int)MainFrameID::spinFrameControl);
    btnGetCameraPara=new wxButton(this,(int)MainFrameID::btnGetCameraPara,wxT("获取相机参数"));
    dirFileSavePath=new wxDirPickerCtrl(this,(int)MainFrameID::dirFileSavePath,wxEmptyString,wxEmptyString,wxDefaultPosition,wxDefaultSize,wxDIRP_SMALL);
    btnFileTransfer=new wxButton(this,(int)MainFrameID::btnFileTransfer,wxT("文件传输"));
    chkControlAll=new wxCheckBox(this,(int)MainFrameID::chkControlAll,wxT("启用全局控制"));
    //deviceList->SetMaxSize(wxSize(200,1000));
    displayArea->SetMinSize(wxSize(700,700));
    SetMinSize(wxSize(800,700));
    txtInf->SetMinSize(wxSize(250,50));
    cameraControl->Add(new wxStaticText(this,wxID_ANY,wxT("图像高度")));
    cameraControl->Add(spinImageHeight,wxSizerFlags().Expand());
    cameraControl->Add(new wxStaticText(this,wxID_ANY,wxT("图像宽度")));
    cameraControl->Add(spinImageWidth,wxSizerFlags().Expand());
    cameraControl->Add(new wxStaticText(this,wxID_ANY,wxT("图像X偏移")));
    cameraControl->Add(spinImageXOffset,wxSizerFlags().Expand());
    cameraControl->Add(new wxStaticText(this,wxID_ANY,wxT("图像Y偏移")));
    cameraControl->Add(spinImageYOffset,wxSizerFlags().Expand());
    cameraControl->Add(new wxStaticText(this,wxID_ANY,wxT("曝光时间")));
    cameraControl->Add(spinExposureTime,wxSizerFlags().Expand());
    cameraControl->Add(new wxStaticText(this,wxID_ANY,wxT("帧率控制")));
    cameraControl->Add(spinFrameControl,wxSizerFlags().Expand());
    cameraControl->AddStretchSpacer();
    cameraControl->Add(chkCameraTrigger,wxSizerFlags().Expand());
    sideBarSizer->Add(txtInf,wxSizerFlags().Expand());
    sideBarSizer->Add(deviceList,wxSizerFlags(1).Expand().Border());
    sideBarSizer->Add(chkControlAll,wxSizerFlags().Expand());
    sideBarSizer->Add(btnInitDevice,wxSizerFlags().Expand());
    sideBarSizer->Add(btnStartShot,wxSizerFlags().Expand());
    sideBarSizer->Add(btnStartSave,wxSizerFlags().Expand());
    sideBarSizer->Add(btnGetDeviceStatus,wxSizerFlags().Expand());
    sideBarSizer->Add(btnGetCameraPara,wxSizerFlags().Expand());
    sideBarSizer->Add(btnFileTransfer,wxSizerFlags().Expand());
    sideBarSizer->Add(dirFileSavePath,wxSizerFlags().Expand());
    sideBarSizer->AddSpacer(2);
    sideBarSizer->Add(new wxStaticText(this,wxID_ANY,wxT("相机参数控制")),wxSizerFlags().CenterHorizontal());
    sideBarSizer->Add(cameraControl,wxSizerFlags().Expand());
    mainSizer->Add(sideBarSizer,wxSizerFlags(0).Expand());
    mainSizer->Add(displayArea,wxSizerFlags(5).Expand());

    serverManage.reset(new ServerManage(this,wxID_ANY));
    SetSizerAndFit(mainSizer);
    deviceList->AppendColumn(wxT("设备名称"));
    deviceList->AppendColumn(wxT("IP地址"));
    deviceList->SetColumnWidth(0,100);
    deviceList->SetColumnWidth(1,100);
    spinImageHeight->SetRange(0,1080);
    spinImageWidth->SetRange(0,1440);
    spinExposureTime->SetRange(0,1000000);
    spinFrameControl->SetRange(0,10000);
    spinImageXOffset->SetRange(0,1440);
    spinImageYOffset->SetRange(0,1080);
    spinFrameControl->SetRange(0,1000);

    Bind(wxEVT_LIST_ITEM_DESELECTED,&MainFrame::on_deviceList_deselect,this,wxID_ANY);
    Bind(wxEVT_LIST_ITEM_SELECTED,&MainFrame::on_deviceList_select,this,wxID_ANY);
    Bind(EVT_SERVER_CONN_NEW,&MainFrame::on_serverConn_new,this,wxID_ANY);
    Bind(EVT_SERVER_CONN_CLOSE,&MainFrame::on_serverConn_close,this,wxID_ANY);
    Bind(EVT_SERVER_NEW_IMAGE,&MainFrame::on_server_newImage,this,wxID_ANY);
    Bind(EVT_DEVICE_MESSAGE,&MainFrame::on_device_message,this,wxID_ANY);
    Bind(wxEVT_BUTTON,&MainFrame::on_btnInitDevice_click,this,(int)MainFrameID::btnInitDevice);
    Bind(wxEVT_BUTTON,&MainFrame::on_btnStartShot_click,this,(int)MainFrameID::btnStartShot);
    Bind(wxEVT_BUTTON,&MainFrame::on_btnStartSave_click,this,(int)MainFrameID::btnStartSave);
    Bind(wxEVT_BUTTON,&MainFrame::on_btnGetDeviceStatus_click,this,(int)MainFrameID::btnGetDeviceStatus);
    Bind(wxEVT_SPINCTRL,&MainFrame::on_spinImageHeight_change,this,(int)MainFrameID::spinImageHeight);
    Bind(wxEVT_SPINCTRL,&MainFrame::on_spinImageWidth_change,this,(int)MainFrameID::spinImageWidth);
    Bind(wxEVT_SPINCTRL,&MainFrame::on_spinImageXOffset_change,this,(int)MainFrameID::spinImageXOffset);
    Bind(wxEVT_SPINCTRL,&MainFrame::on_spinImageYOffset_change,this,(int)MainFrameID::spinImageYOffset);
    Bind(wxEVT_SPINCTRL,&MainFrame::on_spinFrameControl_change,this,(int)MainFrameID::spinFrameControl);
    Bind(wxEVT_SPINCTRL,&MainFrame::on_spinExposureTime_change,this,(int)MainFrameID::spinExposureTime);
    Bind(wxEVT_CHECKBOX,&MainFrame::on_chkCameraTrigger_click,this,(int)MainFrameID::chkCameraTrigger);
    Bind(wxEVT_BUTTON,&MainFrame::on_btnGetCameraPara_click,this,(int)MainFrameID::btnGetCameraPara);
    Bind(wxEVT_BUTTON,&MainFrame::on_btnFileTransfer_click,this,(int)MainFrameID::btnFileTransfer);
    Bind(wxEVT_DIRPICKER_CHANGED,&MainFrame::on_dirFileSavePath_change,this,(int)MainFrameID::dirFileSavePath);
    Bind(wxEVT_CHECKBOX,&MainFrame::on_chkControlAll_change,this,(int)MainFrameID::chkControlAll);

    Bind(EVT_RECEIVEFILE_START,&MainFrame::on_transferFileStart,this,wxID_ANY);
    Bind(EVT_RECEIVEFILE_STOP,&MainFrame::on_transferFileStop,this,wxID_ANY);
    Bind(EVT_RECEIVEFILE_NEW,&MainFrame::on_transferFileNewBlock,this,wxID_ANY);
}

void MainFrame::on_serverConn_new(ServerConnEvent& event)
{
    int InsertPos=0;
    std::string dname= event.GetDeviceName();
    //正则表达式
    std::regex reg(R"(camera_([0-9]+))");
    std::smatch res;
    if(std::regex_match(dname,res,reg))
    {
      int dNum=std::stoi(res[1]);
      for(;InsertPos<deviceList->GetItemCount();InsertPos++)
      {
        std::string now_str=deviceList->GetItemText(InsertPos).ToStdString();
        if(std::regex_match(now_str,res,reg))
        {
            //简易排序:时间复杂度O(0)
            int cNum=std::stoi(res[1]);
            if(cNum>dNum)
              break;
            else
              continue;
        }
        else
        {
          InsertPos++;
          break;
        }
      }
    }
    else
    {
      InsertPos=deviceList->GetItemCount();
    }
    wxListItem newItem;
    newItem.SetData(event.GetDeviceUUID());
    newItem.SetId(InsertPos);
    newItem.SetColumn(0);
    newItem.SetText(wxString().FromUTF8(event.GetDeviceName()));
    deviceList->InsertItem(newItem);
    newItem.SetColumn(1);
    newItem.SetText(wxString().FromUTF8(event.GetIpAddress()));
    deviceList->SetItem(newItem);
}

void MainFrame::on_serverConn_close(ServerConnEvent& event)
{
    for(int i=0;i<deviceList->GetItemCount();i++)
    {
        if(deviceList->GetItemData(i)==event.GetDeviceUUID())
        {
            deviceList->DeleteItem(i);
        }
    }
}

void MainFrame::on_server_newImage(NewImageData& event)
{
    auto size=event.GetSize();
    displayArea->showImage(event.GetImage(),size.GetHeight(),size.GetWidth(),event.GetFormat());
}

void MainFrame::on_deviceList_select(wxListEvent& event)
{
    serverManage->SetDevice(event.GetData());
    try {
      updateUI(serverManage->GetDeviceInfo());
    }   
    catch(const std::exception& e)
    {
        wxMessageBox(wxString().FromUTF8(e.what()),wxT("执行错误"),wxICON_ERROR | wxOK);
        serverManage->SetDevice(-1);
    }
}

void MainFrame::on_deviceList_deselect(wxListEvent& event)
{
    
}

void MainFrame::on_btnInitDevice_click(wxCommandEvent& event)
{
    try
    {

        if(controlAllFlag)
        {
          wxProgressDialog dialog(wxT("批量操作"),wxT("正在向所有设备发送初始化指令"),deviceList->GetItemCount(),this);
          for(int i=0;i<deviceList->GetItemCount();i++)
          {
            dialog.Update(i);
            serverManage->SetDevice(deviceList->GetItemData(i));
            serverManage->InitDevice();
          }
        }
        else
          serverManage->InitDevice();
    updateUI(serverManage->GetDeviceInfo());
    }
    catch(const std::exception& e)
    {
        wxMessageBox(wxString().FromUTF8(e.what()),wxT("执行错误"),wxICON_ERROR | wxOK);
        serverManage->SetDevice(-1);
        return;
    }
    wxCommandEvent evt(wxEVT_BUTTON,(int)MainFrameID::btnGetCameraPara);
    ProcessEvent(evt);
}

void MainFrame::on_btnStartShot_click(wxCommandEvent& event)
{
    try
    {
        if(controlAllFlag)
        {
          wxProgressDialog dialog(wxT("批量操作"),wxT("正在向所有设备发送拍摄指令"),deviceList->GetItemCount(),this);
          for(int i=0;i<deviceList->GetItemCount();i++)
          {
            dialog.Update(i);
            serverManage->SetDevice(deviceList->GetItemData(i));
            serverManage->ControlShot();
          }
        }
        else
          serverManage->ControlShot();
      updateUI(serverManage->GetDeviceInfo());
    }
    catch(const std::exception& e)
    {
        wxMessageBox(wxString().FromUTF8(e.what()),wxT("执行错误"),wxICON_ERROR | wxOK);
        serverManage->SetDevice(-1);
    }
}

void MainFrame::on_btnStartSave_click(wxCommandEvent& event)
{
    try
    {
        if(controlAllFlag)
        {
          wxProgressDialog dialog(wxT("批量操作"),wxT("正在向所有设备发送存图指令"),deviceList->GetItemCount(),this);
          for(int i=0;i<deviceList->GetItemCount();i++)
          {
            dialog.Update(i);
            serverManage->SetDevice(deviceList->GetItemData(i));
            serverManage->ControlCollege();
          }
        }
        else
          serverManage->ControlCollege();
        updateUI(serverManage->GetDeviceInfo());
    }
    catch(const std::exception& e)
    {
        wxMessageBox(wxString().FromUTF8(e.what()),wxT("执行错误"),wxICON_ERROR | wxOK);
        serverManage->SetDevice(-1);
    }
}

void MainFrame::on_btnGetDeviceStatus_click(wxCommandEvent& event)
{
    auto info=serverManage->GetDeviceInfo();
    switch (info)
    {
    case DeviceStatus::UnInit :
        txtInf->SetLabel(wxT("未初始化"));
        break;
    case DeviceStatus::startShot:
        txtInf->SetLabel(wxT("开始拍摄"));
        break;
    case DeviceStatus::startCollege:
        txtInf->SetLabel(wxT("开始存图"));
        break;
    case DeviceStatus::openCamera:
        txtInf->SetLabel(wxT("打开相机"));
        break;
    case DeviceStatus::deviceError:
        txtInf->SetLabel(wxT("设备错误"));
        break;
    case DeviceStatus::connectCamera:
        txtInf->SetLabel(wxT("相机连接"));
        break;
    default:
        break;
    }
}

void MainFrame::on_spinImageHeight_change(wxSpinEvent& event)
{
    if(controlAllFlag)
    {
      wxProgressDialog dialog(wxT("批量操作"),wxT("正在向所有设备发送存图指令"),deviceList->GetItemCount(),this);
      for(int i=0;i<deviceList->GetItemCount();i++)
      {
        dialog.Update(i);
        serverManage->SetDevice(deviceList->GetItemData(i));
        serverManage->SetImageHeight(spinImageHeight->GetValue());
      }
    }
    else
      serverManage->SetImageHeight(spinImageHeight->GetValue());
}

void MainFrame::on_spinImageWidth_change(wxSpinEvent& event)
{
    if(controlAllFlag)
    {
      wxProgressDialog dialog(wxT("批量操作"),wxT("正在向所有设备发送存图指令"),deviceList->GetItemCount(),this);
      for(int i=0;i<deviceList->GetItemCount();i++)
      {
        dialog.Update(i);
        serverManage->SetDevice(deviceList->GetItemData(i));
        serverManage->SetImageWidth(spinImageWidth->GetValue());
      }
    }
    else
      serverManage->SetImageWidth(spinImageWidth->GetValue());
}

void MainFrame::on_spinImageXOffset_change(wxSpinEvent& event)
{
    if(controlAllFlag)
    {
      wxProgressDialog dialog(wxT("批量操作"),wxT("正在向所有设备发送存图指令"),deviceList->GetItemCount(),this);
      for(int i=0;i<deviceList->GetItemCount();i++)
      {
        dialog.Update(i);
        serverManage->SetDevice(deviceList->GetItemData(i));
        serverManage->SetImageOffsetX(spinImageXOffset->GetValue());
      }
    }
    else
      serverManage->SetImageOffsetX(spinImageXOffset->GetValue());
}

void MainFrame::on_spinImageYOffset_change(wxSpinEvent& event)
{
    if(controlAllFlag)
    {
      wxProgressDialog dialog(wxT("批量操作"),wxT("正在向所有设备发送存图指令"),deviceList->GetItemCount(),this);
      for(int i=0;i<deviceList->GetItemCount();i++)
      {
        dialog.Update(i);
        serverManage->SetDevice(deviceList->GetItemData(i));
        serverManage->SetImageOffsetY(spinImageYOffset->GetValue());
      }
    }
    else
      serverManage->SetImageOffsetY(spinImageYOffset->GetValue());
}

void MainFrame::on_spinExposureTime_change(wxSpinEvent& event)
{
    if(controlAllFlag)
    {
      wxProgressDialog dialog(wxT("批量操作"),wxT("正在向所有设备发送存图指令"),deviceList->GetItemCount(),this);
      for(int i=0;i<deviceList->GetItemCount();i++)
      {
        dialog.Update(i);
        serverManage->SetDevice(deviceList->GetItemData(i));
        serverManage->SetExposeTime(spinExposureTime->GetValue());
      }
    }
    else
      serverManage->SetExposeTime(spinExposureTime->GetValue());
}

void MainFrame::on_spinFrameControl_change(wxSpinEvent& event)
{
    if(controlAllFlag)
    {
      wxProgressDialog dialog(wxT("批量操作"),wxT("正在向所有设备发送存图指令"),deviceList->GetItemCount(),this);
      for(int i=0;i<deviceList->GetItemCount();i++)
      {
        dialog.Update(i);
        serverManage->SetDevice(deviceList->GetItemData(i));
        serverManage->SetFrameRate(spinFrameControl->GetValue());
      }
    }
    else
      serverManage->SetFrameRate(spinFrameControl->GetValue());
}

void MainFrame::on_chkCameraTrigger_click(wxCommandEvent& event)
{
    try
    {
      if(controlAllFlag)
      {
        wxProgressDialog dialog(wxT("批量操作"),wxT("正在向所有设备发送存图指令"),deviceList->GetItemCount(),this);
        for(int i=0;i<deviceList->GetItemCount();i++)
        {
          dialog.Update(i);
          serverManage->SetDevice(deviceList->GetItemData(i));
          serverManage->SetTriggerMode(chkCameraTrigger->GetValue());
        }
      }
      else
        serverManage->SetTriggerMode(chkCameraTrigger->GetValue());
    }
    catch(const std::exception& e)
    {
        wxMessageBox(wxString().FromUTF8(e.what()),wxT("执行错误"),wxICON_ERROR | wxOK);
        serverManage->SetDevice(-1);
    }
}

void MainFrame::on_btnGetCameraPara_click(wxCommandEvent& event)
{
    CameraParament para;
    try
    {
        para=serverManage->GetCameraPara();
    }
    catch(const std::exception& e)
    {
        wxMessageBox(wxString().FromUTF8(e.what()),wxT("执行错误"),wxICON_ERROR | wxOK);
        serverManage->SetDevice(-1);
        return;
    }
    
    spinImageHeight->SetValue(para.ImageHeight);
    spinImageWidth->SetValue(para.ImageWidth);
    spinImageXOffset->SetValue(para.ImageOffsetX);
    spinImageYOffset->SetValue(para.ImageOffsetY);
    spinExposureTime->SetValue(para.ExposeTime);
    spinFrameControl->SetValue(para.FrameRate);
    if(para.TriggerMode==0x1)
        chkCameraTrigger->SetValue(true);
    else
        chkCameraTrigger->SetValue(false);
}

void MainFrame::on_device_message(DeviceMessageEvent& event)
{
    txtInf->SetLabel(wxString().FromUTF8(fmt::format("来自设备{}的消息:\n{}",event.GetDeviceId(),event.GetMessage())));
}

void MainFrame::on_dirFileSavePath_change(wxFileDirPickerEvent& event)
{
    fileSavePath=dirFileSavePath->GetPath().ToStdString();
}

void MainFrame::on_btnFileTransfer_click(wxCommandEvent& event)
{
    if(fileSavePath.length()==0)
    {
        wxMessageBox(wxT("请选择一个有效的存储目录"),wxT("消息"),wxOK | wxICON_INFORMATION,this);
        return;
    }
    serverManage->FileTransferFunc(fileSavePath);
}

void MainFrame::on_transferFileStart(ReceiveNewEvent& event)
{
    progDlg.reset(new wxProgressDialog(wxT("文件传输"),wxT("文件接收中"),event.GetIndex(),this));
}

void MainFrame::on_transferFileStop(wxCommandEvent& event)
{
    progDlg.reset(nullptr);
}

void MainFrame::on_transferFileNewBlock(ReceiveNewEvent& event)
{
    progDlg->Update(event.GetIndex(),wxString::Format(L"已传输数据: %ld MB",event.GetIndex()*512/1024/1024));
}

void MainFrame::on_chkControlAll_change(wxCommandEvent& event)
{
  controlAllFlag=chkControlAll->GetValue();
}

void MainFrame::updateUI(DeviceStatus deviceStatus)
{
    switch (deviceStatus)
    {
    case DeviceStatus::deviceError:
        
        break;
    case DeviceStatus::connectCamera:
        break;
    case DeviceStatus::openCamera:
        btnInitDevice->Enable(false);
        btnStartSave->Enable(false);
        btnStartShot->Enable(true);
        SetCameraControlEnable(true);
        btnStartShot->SetLabelText(wxT("开始拍摄"));
        break;
    case DeviceStatus::startShot:
        btnStartSave->Enable(true);
        btnStartShot->SetLabelText(wxT("停止拍摄"));
        btnStartSave->SetLabelText(wxT("开始存图"));
        SetCameraControlEnable(false);
        break;
    case DeviceStatus::startCollege:
        btnStartSave->SetLabelText(wxT("停止存图"));
        SetCameraControlEnable(false);
        break;;
    case DeviceStatus::UnInit:
        btnInitDevice->Enable(true);
        btnStartSave->Enable(false);
        btnStartShot->Enable(false);
        SetCameraControlEnable(false);
        break;
    default:
        break;
    }
}

void MainFrame::SetCameraControlEnable(bool enable)
{
    spinImageHeight->Enable(enable);
    spinImageWidth->Enable(enable);
    spinImageXOffset->Enable(enable);
    spinImageYOffset->Enable(enable);
    spinExposureTime->Enable(enable);
    spinFrameControl->Enable(enable);
    chkCameraTrigger->Enable(enable);
}
